package com.leigq.dynamic.task.web;


import com.leigq.dynamic.task.web.config.DynamicTaskConfig;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.scheduling.support.CronTrigger;
import org.springframework.stereotype.Component;

import java.util.Map;
import java.util.concurrent.ScheduledFuture;

/**
 * 动态任务支持
 * <br/>
 * 动态配置 cron 表达式，立刻生效，支持 停止、重启、更新cron
 *
 * @author leiguoqing
 */
@Slf4j
@Component
public class DynamicTaskSupport {

    /**
     * Future handles, to cancel the running jobs
     */
    private final Map<String, ScheduledFuture<?>> futureMap;

    /**
     * 获取 定时任务的具体的类，用于后期 重启，更新等操作
     */
    private final Map<String, IDynamicTask> serviceMap;


    /**
     * 句柄，方便后期获取 future
     */
    private final TaskScheduler taskScheduler;


    public DynamicTaskSupport(DynamicTaskConfig dynamicTaskConfig, TaskScheduler dynamicTaskScheduler) {
        futureMap = dynamicTaskConfig.getFutureMap();
        serviceMap = dynamicTaskConfig.getServiceMap();
        taskScheduler = dynamicTaskScheduler;
    }


    /**
     * 新增
     *
     * @param task the task
     * @return the object
     */
    public Boolean add(IDynamicTask task) {
        String type = task.type();
        String cron = task.getTrigger().getExpression();
        if (futureMap.containsKey(type)) {
            log.error("请重新指定任务的 type 属性, type:{}", type);
            return false;
        }
        ScheduledFuture<?> future = taskScheduler.schedule(task.getTask(), task.getTrigger());
        futureMap.put(type, future);
        serviceMap.put(type, task);

        log.info("添加新任务成功: type:{}, cron：{}", type, cron);
        return true;
    }


    /**
     * 更新
     *
     * @param type the type
     * @param cron the cron
     */
    public Boolean update(final String type, final String cron) {
        if (!futureMap.containsKey(type)) {
            log.error("更新失败, 不存在该任务, 请检查 type: {}" + type);
            return false;
        }
        ScheduledFuture<?> future = futureMap.get(type);
        if (future != null) {
            future.cancel(true);
        }
        IDynamicTask service = serviceMap.get(type);
        CronTrigger newTri = service.setTrigger(cron);
        future = taskScheduler.schedule(service.getTask(), newTri);

        // 必须更新一下对象，否则下次cencel 会失败
        futureMap.put(type, future);
        log.info("成功更新执行中的任务，type : {}", type);
        return true;
    }


    /**
     * 取消
     *
     * @param type the type
     * @return the object
     */
    public Boolean cancel(String type) {
        if (!futureMap.containsKey(type)) {
            log.error("取消失败, 不存在该任务, 请检查 type: {}", type);
            return false;
        }
        ScheduledFuture<?> future = futureMap.get(type);
        if (future != null) {
            future.cancel(true);
        }
        futureMap.remove(type);
        log.info("成功取消执行中的任务，type : {}", type);
        return true;
    }

    /**
     * 重启已经存在的任务
     *
     * @param type the type
     * @return the object
     */
    public Boolean restart(String type) {
        IDynamicTask service = serviceMap.get(type);
        if (service == null) {
            log.error("无法启动任务, 不存在该任务, 请检查 type: {}", type);
            return false;
        }

        if (futureMap.containsKey(type)) {
            ScheduledFuture<?> future = futureMap.get(type);
            if (future != null) {
                future.cancel(true);
            }
        }
        ScheduledFuture<?> future = taskScheduler.schedule(service.getTask(), service.getTrigger());

        // 必须更新一下对象，否则下次cencel 会失败
        futureMap.put(type, future);
        log.info("成功重启执行中的任务，type : {}, cron: {}", type, service.getTrigger().getExpression());
        return true;
    }

}
